package base.cipher;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 码生成器,生成不重复数字
 * @author liuboen
 * 
 * since:2012-6-7
 * version:1.0.0
 */
public class CodeGenerator {
	/**
	 * 基础数值
	 */
	private final static char[][] BASE_NUMBER = 	
		{
			{ '7', '2' },
			{ '8', '3' },
			{ '2', '8' },
			{ '4', '5' },
			{ '3', '4' },
			{ '1', '7' },
			{ '5', '0' },
			{ '9', '6' },
			{ '6', '1' }
		};
	
	private final static int[][] DIFF =
		{
			{ -1, 6}, 
			{ 5, 8 },
			{ 2, 0 },
			{ 4, 1 },
			{ 3, 4 },
			{ 6, 3 },
			{ 8, 7 },
			{ 0, 5 },
			{ 1, 2 },
			{ 7, -1 }
		};
	
	/**
	 * 设置基础数值长度
	 */
	private final static int LEN = BASE_NUMBER.length;
    /**
     * 获取随即自动增长序列(并发)
     */
    private final static AtomicInteger SEQ = new AtomicInteger((int)(System.nanoTime()));
    
    /**
     * 设置随即salt
     */
	private final static int CODE_SALT = 91;
    
	/**
	 * 编码的长度
	 */
	private final static int ENCODE_STR_LENGTH = 16;
	
	private final static int MOD = 200;
	
	
	/**
	 * 获取随即数
	 * 
	 * @param mod
	 * @return
	 */
    private static int next(int mod) {
        return (Integer.reverse((int)(SEQ.incrementAndGet() * System.nanoTime())) & 0x7fffffff) % mod;
    }

    private static String encode(long n) {
    	return encode(n, next(MOD));
    }

    private static String encode(long n, long prefix) {
    	n = ((prefix & Long.MAX_VALUE) % MOD + 1) * 1000000000000L + n;
        char[] chs = new char[ENCODE_STR_LENGTH];
        int k = 0;
        int c = 0;
        while (n > 0) {
            c = c * CODE_SALT + (chs[k] = getChar(k, n));
            n /= LEN;
            k++;
        }
        while (k < 15) {
        	c = c * CODE_SALT + (chs[k] = getChar(k, 0));
        	k++;
        }
        c &= Integer.MAX_VALUE;
        for (int i = 15; i < ENCODE_STR_LENGTH; i++) {
        	chs[k] = getChar(i, c);        	
        	c /= LEN;
        	k++;
        }
        return new String(chs);
    }

    private static long decode(String decodeStr) {
    	if (decodeStr == null || decodeStr.length() != ENCODE_STR_LENGTH) {
    		return -1;
    	}
    	char[] chs = decodeStr.toCharArray();
    	int c = 0;
    	for (int i = 0; i < 15; i++) {
    		c = c * CODE_SALT + chs[i];
    	}
    	c &= Integer.MAX_VALUE;
    	for (int i = 15; i < ENCODE_STR_LENGTH; i++) {
    		char n = getChar(i, c);
    		if (chs[i] != n) {
    			return -1;
    		}
    		c /= LEN;
    	}
    	long num = 0;
    	for (int i = 14; i >= 0; i--) {
    		int n = getNum(chs[i], i);
    		if (n < 0) {
    			return -1;
    		}
    		num = num * BASE_NUMBER.length + n;
    	}
    	return num % 1000000000000L;
    }
    
    private static char getChar(int odd, long n) {
    	return BASE_NUMBER[(int)(n % LEN)][odd % 2];
    }
    
    private static int getNum(char c, int odd) {
    	if (c >= '0' && c <= '9') {
    		return DIFF[c - '0'][odd % 2];
    	}
        return -1;
    }

    public static String generate(long consumeCodeDetailID) {
    	return encode(consumeCodeDetailID);
    }
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println(String.valueOf(Long.MAX_VALUE));
		System.out.println(String.valueOf(Long.MAX_VALUE).length());
		System.out.println(BASE_NUMBER.length);
		for (int i = Integer.MAX_VALUE - 10; i < Integer.MAX_VALUE; i++) {
			String enc = generate(i);
			System.out.println(i + " " + enc + " " + decode(enc));
		}
	}
}
